# OmnomBot v2.5 - a little forum IRC bot that has many talents!
# (C) Copyright 2010 Albert H. (alberthro)
# 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# 
# Thanks to everybody at #cemetech and #omnimaga who helped me develop 
# and test this! :D
# 
# Patches are always welcome for new features! ;)
# Project website: http://code.google.com/p/atombot/
# ============================================================================
# To use this bot, you need Python. Install it from http://www.python.org/.
# You may or may not need more modules in order to run this bot.
# 
# Have fun with the bot! :D It's recommended that you change the settings
# below, since they are already in use by another person. (Hint: Me! ;) )
# 
# Changelog:
# v2.5
#   - Added OURL support - this deprecates TinyURL support.
# v2.4
#   - Added New bot behavior support.
# v2.3
#   - Added additional commands
# v2.2
#   - Added bot fallbacking - that is, this bot could act as a "fallback" bot -
#     if one bot died from a crash or connection problem, others could pop in
#     to take the position. Probably use something like zOMinion1, zOMinion2, etc.
#     when not active, then when needed, change it to OmnomBot or Omnom.
#     (zOMinion[n]: z to hide it from sight, OM = OmniMaga/OMnimaga, Minion since
#     the bot is considered to be a follower until the "leader" dies)
# v2.1.8
#   - Moved all the exception handling core to functions.
#   - Moved any exit when fail handling to functions.
#   - Better error printing
#   - Fixed problem with 
#   - Add logging to a file feature, with option to change file name and enable/disable it
#   - Added option to make message printing super silent, errors only.
#   - Added commands to silence or enable the bot
# v2.1.7
#   - Added option to disable dying message on specific channels.
#   - Fixed restart bug (added subprocess module)
# v2.1.6
#   - Added PASS option for server password auth, courtesy of Netham45
#   - Fixed potential problem with TinyURL being down
# v2.1.5
#   - Fixed bot version display.
#   - Added Python version (sys.version) in about message.
#   - Fixed var before global declaration warnings.
#   - Added CALLCHAR option
#   - Added option/feature to allow OPS people to control bot.
#   - Added more commenting for options.
# v2.1
#   - Added restart command to restart the bot.
#   - Fix/Feature: Added proper join/part actions (add/remove chans from CHANNELLIST)
# v2.0
#   - Used xml.dom.minidom instead of xml.parsers.expat to parse forum XML
#   - Shortened code (490 lines instead of 602)!
#   - Faster parsing
#   - About command
#   - Error checks, error message printing after 5 failures, plus shorter exception handling
#   - Proper unicode printing!
# v1.5
#   - Switched XML source from regular RSS to SMF's own XML format
#   - Prints author name now
#   - TinyURLs all the links for shorter output
#   - Trimmed output (for topic titles)
#   - Quicker exit times
#   - Special options for different chans: color, censoring of topic titles
# v1.0
#   - Forked RealBot
#   - Use RSS XML to print forum updates
#   - Use xml.parsers.expat for parsing XML
# 

import sys 
import socket 
import string 
import os 
import traceback
from bs4 import BeautifulSoup
import threading
import urllib, urllib2, httplib
import time
import re, htmlentitydefs
import subprocess
import datetime

# Below are variables that you can alter.

###################################
# Server connection information
###################################

# Server host
HOST = 'irc.mzima.net'
# Server port
PORT = 6667
# IRC nick
NICK = 'MrOmnom'
# IRC password, if needed
PASS = ''
# IRC ident
IDENT = 'Omnom' 
# IRC real name field
REALNAME = 'Omnom' 

###################################
# Bot settings
###################################
# Bot owner
OWNER='alberthro' 
# Channel autoconnect list
CHANNELINIT = [ '#thebot', '#omnimaga' ]#, '#cemetech' ] #The default channel for the bot #'#omnimaga', 
# Channels with colorful output
COLORFULCHANS = [ '#omnimaga', '#thebot' ]
# Channels that can have annoucements when the bot arrives
ANNOUNCECHANS = [ '#thebot' ]
# No death message channels
NODIECHANS = [ '#omnimaga', '#cemetech' ]
# Auto rejoin chans
AUTOREJOIN_CHANS = [ '#thebot' ]
# Bad words list
BADWORDS=[ "boobies", "boobs", "fuck", "shit", "cunt", "dick", "titties", "dick", "tits", "cock", "badwordtest", "fap", "bewb" ]
# Channels that require censoring of explicit words
CLEANCHANS = [ '#cemetech' ]
# Channels that require absolute silence, temporaily or not
SILENTCHANS = [ '#thebot' ]
# Bot call character
CALLCHAR = ">"
# Auto ops people list
OPS=[ 'DJ_Omni', 'Netham45', 'Netbot45', "DJ_O", "alberthro", "Snake_X", "DThought", "Deep_Blue", "Juju", "rcfreak0", "Eeems", "alberthrocks", "juju2143", "Cooliojazz", "alb|ZNC", "alb|57o9", "alb|vps" ]
# Can the people in the OPS list control the bot too? (Like an owner)
# 1 for yes, 0 for no
OPS_CAN_CONTROL_BOT = 1
# Is logging enabled for the bot?
# 1 for yes, 0 for no
LOG_TO_FILE = 1
# Log file name
LOGFILE = "AtomBot-Omnimaga.log"
# Send any errors to the owner?
# 1 for yes, 0 for no
SEND_ERROR_TO_OWNER = 1

###################################
# Forum notification settings
###################################
# Shorten forum links? 
# 1 for yes, 0 for no.
SHORTEN_LINKS = 1
# Shorten titles? (Truncate with ...)
# 1 for yes, 0 for no.
SHORTEN_TITLES = 1
# "New" mode - use the New nick and display new posts with /me (ACTION)?
# 1 for yes, 0 for no.
NEW_NOTIFICATION_MODE=1


###################################
# Bot output/debugging settings
###################################
# Enable debug output?
# 1 for yes, 0 for no. Use 0 unless you are
# trying to debug the bot.
ENABLE_DEBUG = 0
# Enable IRC printing of regular output? 
# 1 for yes, 0 for no. STRONGLY SUGGEST 0!
ENABLE_IRC_PRINT = 0
# Enable IRC printing of debug output?
# 1 for yes, 0 for no. STRONGLY SUGGEST 0!
ENABLE_IRC_PRINT_DEBUG = 0
# Make the bot super silent?
# 1 for yes, 0 for no. This will only print the
# author, and other parts. Nothing else will be 
# printed. Recommended 0 ONLY if you're not debugging,
# nor are interested in who's controlling it.
# Note that this setting OVERRIDES all the other settings!
ENABLE_SUPER_SILENT = 0
###################################
# System settings
###################################
# Allow people to run system commands from IRC?
# 1 for yes, 0 for no.
RUN_SYS_COMMANDS=0

#s.sendall("NICK %s\r\n" % NICK)
###################################
# Bot "minion" mode settings
###################################
# Turn on "minion" mode for the bot. This
# feature allows bot fallbacking. If another
# bot turned off (crash, internet down, or
# closed by accident/on purpose), then the
# bot can take over the position.
# This bot, if this option is on, becomes
# the "minion". It will automatically assign
# itself a name and stay hidden from view.
# 1 for yes, 0 for no
MINION_MODE = 0
# The nick that the minion bot should take over if needed.
MINION_TARGET_NICK = 'Omnom'
# The nick that the minion bot should use while not active.
MINION_NICK = 'zOMinion'
# The chan that the minion bot should join for tracking users.
MINION_WATCH_CHAN = "#thebot"

#OPS=[ 'alberthro', 'qazz42', 'alberth', 'dTal', 'qazzbot', 'DThought', 'AaronBot', 'ArthurH', 'HelloBot', 'MouseBot', 'StickyBot'	 ]

####################################################
# That's all! DO NOT CHANGE ANY VARIABLES BELOW!
####################################################

# Messages from server are stored here - including chat, etc.
readbuffer=''

# Program version
VERSION="2.5"

# Global defines for socket, channel list, IRC connection, 
# thread handle, title and link vars
global s, IRC_CONNECTED
global ForumXMLParseHandler
global CUR_TITLE, CUR_LINK, OLD_TITLE, OLD_LINK
global IN_CHANS

# Internal channel list, blank on start
IN_CHANS = []

# Some definitions for the title and link variables
CUR_TITLE = ""
CUR_LINK = ""
CUR_POSTER = ""
OLD_TITLE = "!"
OLD_LINK = "!"
OLD_POSTER = "!"

# Set the IRC_CONNECTED (IRC connection) variable to 0, since we haven't
# connected yet!
IRC_CONNECTED=0

# Set LOG_FAILED to 0, since nothing has failed yet!
LOG_FAILED = 0

# Create an empty list/array for minion nick list
MINION_NICK_SEARCH = []
# Create a "default" username for printing purposes (this will be 
# overwritten if the bot's activated)
MINION_TEST_NICK = "None, bot not activated"

# Printing functions

# Debug printing
def print_d(string):
	global IRC_CONNECTED
	if ENABLE_DEBUG == 1 and ENABLE_SUPER_SILENT != 1:
		print string
	if (ENABLE_IRC_PRINT_DEBUG == 1 and IRC_CONNECTED == 1):
		s.sendall("PRIVMSG "+CHANNELINIT+" :[OmnomBot] "+string+"\r\n")

# Print to both term and IRC, silencable printing
def print_r(string):
	global IRC_CONNECTED
	if (ENABLE_IRC_PRINT == 1 and IRC_CONNECTED == 1):
		s.sendall("PRIVMSG "+CHANNELINIT+" :[OmnomBot] "+string+"\r\n")
	if ENABLE_SUPER_SILENT != 1:
		print string

# Local print function, no silencing
def print_i(string):
	print string

# Error printing
def print_e(string):
	print string

def findelement(string, thelist):
	"""Return first item in sequence where f(item) == True."""
	print_d("[DEBUG] [FindElement] Search item is "+string)
	print_d("[DEBUG] [FindElement] List to look inside of is "+str(thelist))
	for item in thelist:
		print_d("[DEBUG] [FindElement] String is "+string+", item is "+item)
		if string == item: 
			return True
			break
	return False
def shrinkURL(url):
	tinyurl_api = "http://tinyurl.com/api-create.php?url="
	# Check for name links included in the url (like #here)...
	split_url = url.split('#')
	base_url = split_url[0]
	quoted_url = urllib.quote_plus(base_url)
	
	COUNTED_TFAILS = 0
	
	try:
		tinyurl_conn = urllib2.urlopen(tinyurl_api + quoted_url)
		tinyurl_out = tinyurl_conn.read()
		tinyurl_conn.close()
		COUNTED_TFAILS = 0
		TINYURL_FAILED = 0
	except urllib2.HTTPError, e:
		print_d("[TinyURLCreate] Cannot retrieve URL: HTTP Error Code "+str(e.code))
		COUNTED_TFAILS = COUNTED_TFAILS + 1
		TINYURL_FAILED = 1
	except urllib2.URLError, e:
		print_d("[TinyURLCreate] Cannot retrieve URL: " + str(e.reason[1]))
		COUNTED_TFAILS = COUNTED_TFAILS + 1
		TINYURL_FAILED = 1
	
	if TINYURL_FAILED == 1:
		if COUNTED_TFAILS == 5:
			print_d("[TinyURLCreate] TinyURL is down, posting message...")
			logToFile("[TinyURLCreate] TinyURL is down... (retried 5 times and failed)")
			for chan in IN_CHANS:
				if (not(findelement(chan, SILENTCHANS))):
					s.sendall("PRIVMSG "+chan+" :\x034TinyURL is down at the moment, so some links may not be shortened.\x03\r\n")
		if COUNTED_TFAILS >= 5:
			print_d("[TinyURLCreate] TinyURL is down, returning 1...")
			return 1
		print_d("[TinyURLCreate] Retrying URL creation...")
		retry = shrinkURL(url)
		return retry
	if len(split_url) > 1:
		final_url = tinyurl_out + "#" + split_url[1]
	else:
		final_url = tinyurl_out
	return final_url
'''
def unescape(s):
	s = s.replace("&lt;", "<")
	s = s.replace("&gt;", ">")
	# this has to be last:
	s = s.replace("&amp;", "&")
	return s
'''
def unescape(text):
	def fixup(m):
		text = m.group(0)
		if text[:2] == "&#":
			# character reference
			try:
				if text[:3] == "&#x":
					return unichr(int(text[3:-1], 16))
				else:
					return unichr(int(text[2:-1]))
			except ValueError:
				pass
		else:
			# named entity
			try:
				text = unichr(htmlentitydefs.name2codepoint[text[1:-1]])
			except KeyError:
				pass
		return text # leave as is
	return re.sub("&#?\w+;", fixup, text)
def truncate_me(content, length=30, suffix='...'):
	if len(content) <= length:
		return content
	else:
		return ' '.join(content[:length+1].split(' ')[0:-1]) + suffix
def removeBadWords(thestr):
	for badword in BADWORDS:
		newstr = thestr.replace(badword, '[explicit]')
		thestr = newstr
	return thestr

def CleanString(InputString):
	from string import ascii_letters, digits
	return "".join([ch for ch in InputString if ch in (ascii_letters + digits)])

def getTraceBack():
	et, ev, tb = sys.exc_info()
	while tb :
		co = tb.tb_frame.f_code
		filename = "Filename: " + str(co.co_filename)
		line_no =  "Error line #: " + str(traceback.tb_lineno(tb)) 
		tb = tb.tb_next
	return [filename, line_no, et, ev]

def crashFail(err):
	the_err = getTraceBack()
	fn = the_err[0]
	linen = the_err[1]
	et = the_err[2]
	ev = the_err[3]
	print_i("[CrashHandler] ERROR: Python crashed with: "+str(err)+" on line "+str(linen))
	print_i("[CrashHandler] Error type: "+str(et))
	print_i("[CrashHandler] Detailed error: "+str(ev))
	print_i("[CrashHandler] Traceback:")
	
	logToFile("[CrashHandler] ERROR: Python crashed with: "+str(err)+" on line "+str(linen))
	logToFile("[CrashHandler] Error type: "+str(et))
	logToFile("[CrashHandler] Detailed error: "+str(ev))
	logToFile("[CrashHandler] Traceback:")
	
	#traceback.print_exc(file=sys.stdout)
	exception_split = str(traceback.format_exc()).split("\n")
	for line in exception_split:
		print_i("[CrashHandler] "+line)
		logToFile("[CrashHandler] "+line)
	for chan in IN_CHANS: 
		if findelement(chan, NODIECHANS):
			print_d("Not showing message to "+chan+" due to settings...")
		else:
			if (not(findelement(chan, SILENTCHANS))):
				s.sendall("PRIVMSG "+chan+" :\x034I died - hopefully "+OWNER+" sees the error and fixes it. X_X\x03\r\n")
	if SEND_ERROR_TO_OWNER == 1:
		s.sendall("PRIVMSG "+OWNER+" :\x034I died - hopefully "+OWNER+" sees the error and fixes it. X_X\x03\r\n")
		s.sendall("PRIVMSG "+OWNER+" :\x034ERROR: Python crashed with: "+str(err)+" on line "+str(linen)+"\x03\r\n")
		s.sendall("PRIVMSG "+OWNER+" :\x034Error type: "+str(et)+"\x03\r\n")
def minorCrashFail(err):
	the_err = getTraceBack()
	fn = the_err[0]
	linen = the_err[1]
	et = the_err[2]
	ev = the_err[3]
	print_i("[CrashHandler] ERROR: Python crashed with: "+str(err)+" on line "+str(linen))
	print_i("[CrashHandler] Error type: "+str(et))
	print_i("[CrashHandler] Detailed error: "+str(ev))
	print_i("[CrashHandler] Traceback:")
	
	logToFile("[CrashHandler] ERROR: Python crashed with: "+str(err)+" on line "+str(linen))
	logToFile("[CrashHandler] Error type: "+str(et))
	logToFile("[CrashHandler] Detailed error: "+str(ev))
	logToFile("[CrashHandler] Traceback:")
	#traceback.print_exc(file=sys.stdout)
	exception_split = str(traceback.format_exc()).split("\n")
	for line in exception_split:
		print_i("[CrashHandler] "+line)
		logToFile("[CrashHandler] "+line)
def failExitBot():
	s.sendall("Junk stuff to get bot to exit\r\n")
	s.close()
	exit(1)

def logToFile(log):
	if LOG_TO_FILE == 1:
		try:
			logfh = open(LOGFILE, "a")
			curdt = datetime.datetime.now().strftime("[Omnombot | %m/%d/%Y %I:%M:%S %p]") 
			logfh.write(str(curdt)+" "+log+"\n")
			logfh.close()
		except Exception, err:
			if LOG_FAILED != 1:
				print_e("[Logger] ==========================================================")
				print_e("[Logger] ERROR: Failed to log to file! Make sure that the file is")
				print_e("[Logger] accessible, and that you have the proper permissions to ")
				print_e("[Logger] write to the file (or in the directory).")
				print_e("[Logger] ==========================================================")
				LOG_FAILED = 1
def checkLogFilePerm():
	if LOG_TO_FILE == 1:
		try:
			logfh = open(LOGFILE, "a")
			logfh.close()
		except Exception, err:
			print_e("[Logger] ==========================================================")
			print_e("[Logger] ERROR: The bot has detected that there is no way to write")
			print_e("[Logger] to the log file, since permissions for the file are")
			print_e("[Logger] limited. Make the log file writable, and then try again.")
			print_e("[Logger] Alternatively, you may disable the logging feature by")
			print_e("[Logger] setting LOG_TO_FILE to 0 (inside the script, not")
			print_e("[Logger] environmental variable).")
			print_e("[Logger] ==========================================================")
			exit(1)
def startLog():
	if LOG_TO_FILE == 1:
		startdt = datetime.datetime.now().strftime("%m/%d/%Y at %I:%M:%S %p") 
		logToFile("=====================================================================")
		logToFile("Log start: "+startdt)
		logToFile("=====================================================================")
def joinChannel(chan):
	global s, IN_CHANS
	if(not(findelement(chan, IN_CHANS))):
		s.sendall("JOIN %s \r\n" % chan)
		IN_CHANS.append(chan)
def leaveChannel(chan):
	global s, IN_CHANS
	if(findelement(chan, IN_CHANS)):
		s.sendall("PART %s \r\n" % chan)
		IN_CHANS.remove(chan)

class RestartThread ( threading.Thread ):
	def __init__ ( self, channel, details ):
		self.stopnow = 0
		threading.Thread.__init__(self)
	def stopThread(self):
		print_r("[RestartThread] Got signal to exit.")
		self.stopnow = 1
	def checkExit(self):
		if self.stopnow == 1:
			print_r("Adios from RestartThread thread!")
			exit()
	def run (self):
		print_i("[RestartThread] Waiting for restart...")
		time.sleep(5)
		print_i("[RestartThread] Launching bot...")
		subprocess.Popen([sys.executable, sys.argv[0]])
		print_i("[RestartThread] Launched bot, closing thread...")
		exit()

class ForumXMLParse ( threading.Thread ):
	def __init__ ( self, channel, details ):
		self.stopnow = 0
		threading.Thread.__init__(self)
	def stopThread(self):
		print_r("[ForumXMLParse] Got signal to exit.")
		self.stopnow = 1
	def checkExit(self):
		if self.stopnow == 1:
			print_r("Au revoir from ForumXMLParse thread!")
			exit()
	def run (self):
		print_d("[ForumXMLParse] Pausing before starting loop...")
		time.sleep(5)
		try: 
			while self.stopnow != 1:
				global GO_PARSE, FETCH_TITLE, FETCH_LINK, CUR_TITLE, CUR_LINK, BUILDING_DONE, OLD_TITLE, OLD_LINK, NO_POST
				global INSIDE_TOPIC_TAG, OUT_OF_BOARD_TAG, INSIDE_POSTER_TAG, FETCH_POSTER, OLD_POSTER, CUR_POSTER
				global s
				print_d("[ForumXMLParse] Beginning loop...")
				
				# NOT USING THIS ANYMORE: Fetch from here: http://www.omnimaga.org/index.php?www;action=.xml;type=rss;sa=recent;limit=1
				# Fetch from here: http://www.omnimaga.org/index.php?action=.xml;limit=1
				print_d("[ForumXMLParse] Fetching update...")
				try:
					#rss_src = urllib2.urlopen("http://www.omnimaga.org/index.php?www;action=.xml;type=rss;sa=recent;limit=1")
					rss_src = urllib2.urlopen("http://www.omnimaga.org/index.php?action=.xml;limit=1")
					rssxml = rss_src.read()
					rss_src.close()
					HTTP_FAIL = 0
					COUNTED_FAILS = 0
				except urllib2.HTTPError, e:
					print_d("[ForumXMLParse] Cannot retrieve URL: HTTP Error Code "+str(e.code))
					COUNTED_FAILS = COUNTED_FAILS + 1
					HTTP_FAIL = 1
				except urllib2.URLError, e:
					print_d("[ForumXMLParse] Cannot retrieve URL: " + str(e.reason[1]))
					COUNTED_FAILS = COUNTED_FAILS + 1
					HTTP_FAIL = 1
				except httplib.BadStatusLine, e:
					print_d("[ForumXMLParse] Cannot retrieve URL: HTTP server sent a weird status message; maybe connection was messed up?")
					COUNTED_FAILS = COUNTED_FAILS + 1
					HTTP_FAIL = 1
				except Exception, err:
					print_d("[ForumXMLParse] Cannot retrieve URL: Unknown error. A stack trace will now be dumped.")
					crashFail(err)
				
				if HTTP_FAIL == 0:
					print_d("[ForumXMLParse] Parsing XML...")
					# xml_data = minidom.parseString(data).getElementsByTagName('smf:xml-feed')
					# parts = xml_data[0].getElementsByTagName('recent-post')
					# parts_poster = parts[0].getElementsByTagName('poster')[0].getElementsByTagName('name')[0].firstChild.nodeValue
					# parts_topic = parts[0].getElementsByTagName('subject')[0].firstChild.wholeText
					# parts_link = parts[0].getElementsByTagName('link')[-1].firstChild.nodeValue
					try:
						# BeautifulSoup... so beautiful.
						soup = BeautifulSoup(rssxml)
						CUR_POSTER = str(soup.poster.find_all('name')[0].contents[0])
						CUR_TITLE = str("".join(soup.topic.subject.contents))
						CUR_LINK = str(soup.find_all("link")[-1].contents[0])
						CUR_TOPICID = str(soup.topic.id.contents[0])
						CUR_POSTID = str(soup.id.contents[0])
					except Exception, err:
						print_e("[ForumXMLParse] Caught XML parse error!")
						crashFail(err)
						failExitBot()
					
					if OLD_LINK != CUR_LINK:
						print_d("[ForumXMLParse] Posting update from Omnimaga!")
						OLD_LINK = CUR_LINK
						
						FINALURL_DISPLAY = "http://ourl.ca/"+CUR_TOPICID+"/"+CUR_POSTID
						
						if SHORTEN_TITLES == 1:
							FINALTITLE_DISPLAY = truncate_me(removeBadWords(unescape(CUR_TITLE)))
							PRINTABLE_TITLE = truncate_me(unescape(CUR_TITLE))
						else:
							FINALTITLE_DISPLAY = removeBadWords(unescape(CUR_TITLE))
							PRINTABLE_TITLE = unescape(CUR_TITLE)
						
						FINALPOSTER_DISPLAY = unescape(CUR_POSTER)
						for chan in IN_CHANS:
							if (findelement(chan, COLORFULCHANS)):
								if (findelement(chan, CLEANCHANS)):
									if (not(findelement(chan, SILENTCHANS))):
										if NEW_NOTIFICATION_MODE == 1:
											s.sendall(unicode("PRIVMSG "+chan+" :\001ACTION \x0310post by \x0303"
														+FINALPOSTER_DISPLAY+"\x0310 in \x0304"+FINALTITLE_DISPLAY
														+"\x0312 \x02\x02"+FINALURL_DISPLAY+"\x03\001\r\n").encode("utf-8"))
										else:
											s.sendall(unicode("PRIVMSG "+chan+" :\x0312(O) \x0310New post by \x0303"
														+FINALPOSTER_DISPLAY+"\x0310 in \x0304"+FINALTITLE_DISPLAY
														+"\x0312 \x02\x02"+FINALURL_DISPLAY+"\x03\r\n").encode("utf-8"))
								else:
									if (not(findelement(chan, SILENTCHANS))):
										if NEW_NOTIFICATION_MODE == 1:
											s.sendall(unicode("PRIVMSG "+chan+" :\001ACTION \x0310post by \x0303"
														+FINALPOSTER_DISPLAY+"\x0310 in \x0304"+PRINTABLE_TITLE
														+"\x0312 \x02\x02"+FINALURL_DISPLAY+"\x03\001\r\n").encode("utf-8"))
										else:
											s.sendall(unicode("PRIVMSG "+chan+" :\x0312(O) \x0310New post by \x0303"
														+FINALPOSTER_DISPLAY+"\x0310 in \x0304"+PRINTABLE_TITLE
														+"\x0312 \x02\x02"+FINALURL_DISPLAY+"\x03\r\n").encode("utf-8"))
							else:
								if (findelement(chan, CLEANCHANS)):
									if (not(findelement(chan, SILENTCHANS))):
										if NEW_NOTIFICATION_MODE == 1:
											s.sendall(unicode("PRIVMSG "+chan+" :\001ACTION post by "+FINALPOSTER_DISPLAY
														+" in "+FINALTITLE_DISPLAY+" "+FINALURL_DISPLAY+"\001\r\n").encode("utf-8"))
										else:
											s.sendall(unicode("PRIVMSG "+chan+" :(O) New post by "+FINALPOSTER_DISPLAY
														+" in "+FINALTITLE_DISPLAY+" "+FINALURL_DISPLAY+"\r\n").encode("utf-8"))
								else:
									if (not(findelement(chan, SILENTCHANS))):
										if NEW_NOTIFICATION_MODE == 1:
											s.sendall(unicode("PRIVMSG "+chan+" :\001ACTION post by "+FINALPOSTER_DISPLAY
														+" in "+PRINTABLE_TITLE+" "+FINALURL_DISPLAY+"\001\r\n").encode("utf-8"))
										else:
											s.sendall(unicode("PRIVMSG "+chan+" :(O) New post by "+FINALPOSTER_DISPLAY
														+" in "+PRINTABLE_TITLE+" "+FINALURL_DISPLAY+"\r\n").encode("utf-8"))
				else:
					if COUNTED_FAILS == 5:
						print_d("Failed to retrieve page after 5 retries, notifying chan.")
						logToFile("[ForumXMLParse] Failed to retrieve page after 5 retries! Chans have been notified.")
						for chan in IN_CHANS: 
							if (not(findelement(chan, SILENTCHANS))):
								s.sendall("PRIVMSG "+chan+" :\x034Currently the Omnimaga site is down (failed after 5 retries), so you may not see any post updates from this bot. Updates will resume when the site goes back up.\x03\r\n")
				print_d("[ForumXMLParse] Waiting for 5 seconds before refreshing...")
				self.checkExit()
				time.sleep(5)
				print_d('[ForumXMLParse] Refreshing...')
			
		except Exception, err:
			print_e("[ForumXMLParse] Caught error!")
			crashFail(err)
			failExitBot()
		print_d("[ForumXMLParse] Exited loop.")

def parsemsg(msg): 
	global ForumXMLParseHandler
	print_r("[ParseMsg] Parsing message...")
	# IPv6 breaks some things
	# :alb|ZNC!albert@2607:fcd0:100:c21:216:3cff:fead:91a PRIVMSG #nspire-lua :%lua2tns
	#complete=msg[1:].split(':',1) #Parse the message into useful data
	#info=complete[0].split(' ')
	#msgpart=complete[1]
	#sender=info[0].split('!')
	
	# USEFUL VARIABLES: info, msgpart, and sender
	info = msg[1:].split(" ")[:-1]
	#msgpart = msg[1:].split(" ")[-1][1:]
	msgpart = " ".join(msg[1:].split(" ")[3:])[1:]
	sender = msg[1:].split(" ")[0].split("!")
	
	if len(msgpart) != 0:
		print_d("[DEBUG] msgpart[0] is "+msgpart[0])
	else:
		return 1
	print_d("[DEBUG] sender[0] is "+sender[0].strip(' '))
	print_d("[DEBUG] msgpart[0] is "+msgpart[0])
	print_d("[DEBUG] info[2] is "+info[2])
	print_d("[DEBUG] OWNER is "+OWNER)
	if msgpart[0]==CALLCHAR:
		print_d("[DEBUG] msgpart is verified!")
	if sender[0].strip(' ')==OWNER:
		print_d("[DEBUG] sender/OWNER is verified!")
	# This change allows anyone to access
	#if msgpart[0] == CALLCHAR:
	
	if msgpart[0]==CALLCHAR and (sender[0].strip(' ')==OWNER or (OPS_CAN_CONTROL_BOT == 1 and findelement(sender[0].strip(' '), OPS))):
		print_r("[ParseMsg] Looking for commands...")
		
		print_d("[ParseMsg] [DEBUG] Spliting command...")
		
		print_d("[DEBUG] msgpart[1:] is "+str(msgpart[1:]))
		cmd=msgpart[1:].split(' ') 
		
		if len(cmd) == 0:
			return 1
		
		if len(cmd) > 1:
			print_d("[DEBUG] cmd[1] is "+str(cmd[1]))
		
		print_r("[ParseMsg] Found command "+str(cmd[0]))
		if cmd[0]=='op': 
			if len(cmd) < 2:
				s.sendall('MODE '+info[2]+' +o '+sender[0]+'\n') 
				print_r("[ParseMsg] Op-ed "+sender[0]+" in "+info[2]+"...")
			else:
				s.sendall('MODE '+info[2]+' +o '+cmd[1]+'\n') 
				print_r("[ParseMsg] Op-ed "+cmd[1]+" in "+info[2]+"...")
		if cmd[0]=='deop': 
			if len(cmd) < 2:
				s.sendall('MODE '+info[2]+' -o '+sender[0]+'\n') 
				print_r("[ParseMsg] Deop-ed "+sender[0]+" in "+info[2]+"...")
			else:
				s.sendall('MODE '+info[2]+' -o '+cmd[1]+'\n') 
				print_r("[ParseMsg] Deop-ed "+cmd[1]+" in "+info[2]+"...")
		if cmd[0]=='voice': 
			if len(cmd) < 2:
				s.sendall('MODE '+info[2]+' +v '+sender[0]+'\n') 
				print_r("[ParseMsg] Voiced "+sender[0]+" in "+info[2]+"...")
			else:
				s.sendall('MODE '+info[2]+' +v '+cmd[1]+'\n') 
				print_r("[ParseMsg] Voiced "+cmd[1]+" in "+info[2]+"...")
		if cmd[0]=='devoice': 
			if len(cmd) < 2:
				s.sendall('MODE '+info[2]+' -v '+sender[0]+'\n') 
				print_r("[ParseMsg] Devoiced "+sender[0]+" in "+info[2]+"...")
			else:
				s.sendall('MODE '+info[2]+' -v '+cmd[1]+'\n') 
				print_r("[ParseMsg] Devoiced "+cmd[1]+" in "+info[2]+"...")
		if cmd[0]=='sys': 
			if RUN_SYS_COMMANDS == 1:
				syscmd(msgpart[1:],info[2]) 
				print_r("[ParseMsg] Running "+msgpart[1]+"...")
			else:
				s.sendall("PRIVMSG "+info[2]+" :System commands are not allowed to be ran. To allow them,\r\n")
				s.sendall("PRIVMSG "+info[2]+" :set RUN_SYS_COMMANDS to 1.\r\n")
		if cmd[0]=='up': 
			s.sendall("PRIVMSG "+info[2]+" :Doing fine. How about you?\r\n")
		if cmd[0]=='leave':
			if len(cmd) < 2:
				leaveChannel(info[2])
				print_r("[ParseMsg] Leaving channel "+info[2]+"...")
			else:
				leaveChannel(cmd[1])
				print_r("[ParseMsg] Leaving channel "+cmd[1]+"...")
		if cmd[0]=='join':
			if len(cmd) < 2:
				joinChannel(info[2])
				print_r("[ParseMsg] Joining channel "+info[2]+"...")
			else:
				joinChannel(cmd[1])
				print_r("[ParseMsg] Joining channel "+cmd[1]+"...")
		if cmd[0]=='silence':
			if len(cmd) < 2:
				SILENTCHANS.append(info[2])
				print_r("[ParseMsg] Silencing bot in channel "+info[2]+"...")
			else:
				SILENTCHANS.append(cmd[1])
				print_r("[ParseMsg] Silencing bot in channel "+cmd[1]+"...")
		if cmd[0]=='enable':
			if len(cmd) < 2:
				SILENTCHANS.remove(info[2])
				print_r("[ParseMsg] Enabling bot in channel "+info[2]+"...")
			else:
				SILENTCHANS.remove(cmd[1])
				print_r("[ParseMsg] Enabling bot in channel "+cmd[1]+"...")
		if cmd[0]=='about':
			if MINION_MODE == 1:
				s.sendall("PRIVMSG "+info[2]+" :\x034OmnomBot v"+str(VERSION)+" by Albert H (alberthro) | Python version:\x0310 "
					+str(sys.version).replace(' \n', ', compiled with ')+"\x034 | XML Core:\x0310 xml.dom.minidom\x034 | Bot owner:\x033 "
					+OWNER+" \x034| Minion username: \x0310"+MINION_TEST_NICK
					+" \x0304| Licensed under GPL v3 | Thanks to everybody at \x0302#cemetech \x0304and \x0302#omnimaga \x0304who helped me develop and test this! :D"
					+" | Website: \x032http://code.google.com/p/atombot/\x0F\r\n")
			else:
				if NEW_NOTIFICATION_MODE == 1:
					s.sendall("PRIVMSG "+info[2]+" :\x034OmnomBot v"+str(VERSION)+" by Albert H (alberthro) | Python version:\x0310 "
						+str(sys.version).replace(' \n', ', compiled with ')+"\x034 | XML Core:\x0310 BeautifulSoup\x034 | Bot owner:\x033 "
						+OWNER+" \x034| Using 'New' bot emulation | Licensed under GPL v3 | Thanks to everybody at \x0302#cemetech \x0304and \x0302#omnimaga \x0304who helped me develop and test this! :D"
						+" | Website: \x032http://code.google.com/p/atombot/\x0F\r\n")
				else:
					s.sendall("PRIVMSG "+info[2]+" :\x034OmnomBot v"+str(VERSION)+" by Albert H (alberthro) | Python version:\x0310 "
						+str(sys.version).replace(' \n', ', compiled with ')+"\x034 | XML Core:\x0310 BeautifulSoup\x034 | Bot owner:\x033 "
						+OWNER+" \x034| Licensed under GPL v3 | Thanks to everybody at \x0302#cemetech \x0304and \x0302#omnimaga \x0304who helped me develop and test this! :D"
						+" | Website: \x032http://code.google.com/p/atombot/\x0F\r\n")
		if cmd[0]=='restart':
			print_r("[ParseMsg] Restarting bot...")
			s.sendall("PRIVMSG "+info[2]+" :\x034Restarting MrOmnom... (If this bot does not come back online, you're screwed - ask alberthrocks to start it up again.)\x0F\r\n")
			ForumXMLParseHandler.stopThread()
			s.sendall("Junk stuff to get bot to exit\r\n")
			s.close()
			RestartThreadHandler = RestartThread(None, "")
			RestartThreadHandler.start()
			exit()
		if cmd[0]=='quit': 
			print_r("[ParseMsg] Exiting bot and closing socket...")
			s.sendall("PRIVMSG "+info[2]+" :MrOmnom out! :D (If this was unintentional, you're screwed - ask alberthrocks to start it up again.)\r\n")
			s.close()
			ForumXMLParseHandler.stopThread()
			exit()
		if cmd[0]=='nick':
			if len(cmd) < 2:
				print_r("[ParseMsg] Changing nick to "+info[2]+"...")
				NICK = info[2]
				s.sendall("NICK %s\r\n" % info[2])
			else:
				print_r("[ParseMsg] Changing nick to "+cmd[1]+"...")
				NICK = cmd[1]
				s.sendall("NICK %s\r\n" % cmd[1])
		if cmd[0]=='say':
			if len(cmd) < 2:
				print_r("[ParseMsg] User wanted to make the bot say something, but didn't specify what to say...")
				s.sendall("PRIVMSG "+info[2]+" :What to say?\r\n")
			else:
				print_r("[ParseMsg] Saying words... (Word is "+str(" ".join(cmd[1:]))+")")
				s.sendall("PRIVMSG "+info[2]+" :"+str(" ".join(cmd[1:]))+"\r\n")
		if cmd[0]=='announce':
			if len(cmd) < 2:
				print_r("[ParseMsg] User wanted to make the bot announce something, but didn't specify what to say...")
				s.sendall("PRIVMSG "+info[2]+" :What to announce?\r\n")
			else:
				print_r("[ParseMsg] Announcing service request... (Announcement is "+str(" ".join(cmd[1:]))+")")
				nocolor_regex = re.compile("\x03(?:\d{1,2}(?:,\d{1,2})?)?", re.UNICODE)
				nocolor_msg = nocolor_regex.sub("", str(" ".join(cmd[1:])))
				for chan in IN_CHANS:
					if (not(findelement(chan, SILENTCHANS))):
						if (NEW_NOTIFICATION_MODE == 1) and (nocolor_msg[:2] == "is"):
							if (findelement(chan, COLORFULCHANS)):
								s.sendall("PRIVMSG "+chan+" :\001ACTION "+str(" ".join(cmd[1:]))+"\001\r\n")
							else:
								s.sendall("PRIVMSG "+chan+" :\001ACTION "+nocolor_msg+"\001\r\n")
						else:
							if (findelement(chan, COLORFULCHANS)):
								s.sendall("PRIVMSG "+chan+" :"+str(" ".join(cmd[1:]))+"\r\n")
							else:
								s.sendall("PRIVMSG "+chan+" :"+nocolor_msg+"\r\n")
		if cmd[0]=='announce_service':
			print_r("[ParseMsg] Announcing service request...")
			s.sendall("PRIVMSG "+info[2]+" :Announcing service request to all non-muted channels.\r\n")
			for chan in IN_CHANS:
				if (not(findelement(chan, SILENTCHANS))):
					if NEW_NOTIFICATION_MODE == 1:
						if (findelement(chan, COLORFULCHANS)):
							s.sendall("PRIVMSG "+chan+" :\001ACTION \x034is being serviced and may quit, restart, or not respond. I'll be back soon!\x0F\001\r\n")
						else:
							s.sendall("PRIVMSG "+chan+" :\001ACTION is being serviced and may quit, restart, or not respond. I'll be back soon!\001\r\n")
					else:
						if (findelement(chan, COLORFULCHANS)):
							s.sendall("PRIVMSG "+chan+" :\x034This bot is now being serviced and may quit, restart, or not respond. This bot will be back soon!\x0F\r\n")
						else:
							s.sendall("PRIVMSG "+chan+" :This bot is now being serviced and may quit, restart, or not respond. This bot will be back soon!\r\n")
		if cmd[0]=='announce_service_done':
			print_r("[ParseMsg] Announcing service completion...")
			s.sendall("PRIVMSG "+info[2]+" :Announcing service completion to all non-muted channels.\r\n")
			for chan in IN_CHANS:
				if (not(findelement(chan, SILENTCHANS))):
					if NEW_NOTIFICATION_MODE == 1:
						if (findelement(chan, COLORFULCHANS)):
							s.sendall("PRIVMSG "+chan+" :\001ACTION \x034is done being serviced! Thanks for being patient!\x0F\001\r\n")
						else:
							s.sendall("PRIVMSG "+chan+" :\001ACTION is done being serviced! Thanks for being patient!\001\r\n")
					else:
						if (findelement(chan, COLORFULCHANS)):
							s.sendall("PRIVMSG "+chan+" :\x034This bot is done being serviced! Thanks for being patient!\x0F\r\n")
						else:
							s.sendall("PRIVMSG "+chan+" :This bot is done being serviced! Thanks for being patient!\r\n")
		if cmd[0]=='raw':
			if len(cmd) < 2:
				print_r("[ParseMsg] User wanted to make the bot execute a raw command in IRC, but didn't specify what to execute...")
				s.sendall("PRIVMSG "+info[2]+" :What to execute?\r\n")
			else:
				print_r("[ParseMsg] Executing command... (Command is "+str(" ".join(cmd[1:]))+")")
				s.sendall(str(" ".join(cmd[1:]))+"\r\n")
		if cmd[0]=='me':
			# Protocol: PRIVMSG #chan :\001ACTION doing something\001 (and \r\n)
			if len(cmd) < 2:
				print_r("[ParseMsg] User wanted to make the bot do an ACTION in IRC, but didn't specify what to do...")
				s.sendall("PRIVMSG "+info[2]+" :\001ACTION doesn't know What to execute...\001\r\n")
			else:
				print_r("[ParseMsg] Sending /me.. (Action is is "+str(" ".join(cmd[1:]))+")")
				s.sendall("PRIVMSG "+info[2]+" :\001ACTION "+str(" ".join(cmd[1:]))+"\001\r\n")

		 
	#if msgpart[0]=='-' and sender[0]==OWNER : #Treat msgs with - as explicit command to send to server 
	#	cmd=msgpart[1:] 
	#	print_r("[ParseMsg] Got command from channel: "+cmd[1]+"...")
	#	s.sendall(cmd+'n') 
	#	print 'cmd='+cmd 

def syscmd(commandline,channel): 
	cmd=commandline.replace('sys ','') 
	cmd=cmd.rstrip() 
	os.system(cmd+' >temp.txt') 
	a=open('temp.txt') 
	ot=a.read() 
	ot.replace('n','|') 
	a.close() 
	s.sendall('PRIVMSG '+channel+' :'+ot+'n') 
	return 0 

print_i("OmnomBot v"+str(VERSION)+" by Albert H")
print_i("==============================")
print_i("Starting IRC bot...")
print_i("")

checkLogFilePerm()
startLog()

s=socket.socket( )
s.connect((HOST, PORT))
if PASS != '':
	s.sendall("PASS %s\r\n" % PASS)
if NEW_NOTIFICATION_MODE == 1:
	# Force the nick to be "New"
	NICK = "New"
s.sendall("NICK %s\r\n" % NICK)
s.sendall("USER %s %s bla :%s\r\n" % (IDENT, HOST, REALNAME))

if MINION_MODE == 1:
	#[IRC] :irc.choopa.net 433 Omnom qazz42 :Nickname is already in use.
	print_i("Entering Minion mode...")
	s.sendall("NICK %s\r\n" % MINION_TARGET_NICK)
	NICKNAME_TAKEN = 0
	MINION_CHECK_RETRIES = 0
	DONE_CHECK = 0
	while DONE_CHECK == 0:
		try:
			readbuffer=readbuffer+s.recv(500)
			temp=string.split(readbuffer, "\n")
			readbuffer=temp.pop()
			
			for line in temp:
				print_r("[IRC | MinionCheck] "+line)
				line=string.rstrip(line)
				line=string.split(line)
				
				if(line[0] == ':'+HOST and str(" ".join(line)).find('Nickname is already in use.') != -1):
					print "Setting NICKNAME_TAKEN to 1..."
					NICKNAME_TAKEN = 1
					DONE_CHECK = 1
				if(line[0]=="PING"):
					s.sendall("PONG %s\r\n" % line[1])
		except:
			print_i("Connection failed, exiting.")
			exit(1)
		MINION_CHECK_RETRIES = MINION_CHECK_RETRIES + 1
		if MINION_CHECK_RETRIES == 10:
			DONE_CHECK = 1
		time.sleep(0.75)
	print "Checking for failure..."
	if NICKNAME_TAKEN == 1:
		print_i("Target nickname taken - going into minion mode...")
		MINION_NICK_SEARCH.append(MINION_TARGET_NICK)
		
		# Begin some brute forcing...
		MINION_LOCKED_USERNAME = 0
		MINION_NUMBER_SUFFIX = 1
		NICKNAME_TAKEN = 0
		while MINION_LOCKED_USERNAME == 0:
			try:
				MINION_TEST_NICK = MINION_NICK + str(MINION_NUMBER_SUFFIX)
				s.sendall("NICK %s\r\n" % MINION_TEST_NICK)
				
				readbuffer=readbuffer+s.recv(1024)
				temp=string.split(readbuffer, "\n")
				readbuffer=temp.pop()
				
				for line in temp:
					print_r("[IRC | MinionBot] "+line)
					line=string.rstrip(line)
					line=string.split(line)
					
					if(line[0]=="PING"):
						s.sendall("PONG %s\r\n" % line[1])
					
					if(line[0] == ':'+HOST and str(" ".join(line)).find(':Nickname is already in use.') != -1):
						NICKNAME_TAKEN = 1
					else:
						NICKNAME_TAKEN = 0
					
				if NICKNAME_TAKEN == 0:
					MINION_LOCKED_USERNAME = 1
				else:
					MINION_NICK_SEARCH.append(MINION_TEST_NICK)
					MINION_NUMBER_SUFFIX = MINION_NUMBER_SUFFIX + 1
				
			except:
				print_i("Connection failed, exiting.")
				exit(1)
		# Now that we have secured a nick, and gotten a list of things to watch, let's
		# actually enter MINION mode! :D
		joinChannel(MINION_WATCH_CHAN)
		MINION_READY = 0
		
		MINION_START = 0
		MINION_CALLED_COMMAND = 0
		
		while MINION_READY == 0:
			readbuffer2 = ""
			if MINION_START == 1:
				s.sendall("NAMES %s\r\n" % MINION_WATCH_CHAN)
				MINION_CALLED_COMMAND = 1
			try:
				readbuffer2=readbuffer2+s.recv(1024)
				temp=string.split(readbuffer2, "\n")
				readbuffer2=temp.pop()
				
				for line in temp:
					print_r("[IRC | MinionBot] "+line)
					line=string.rstrip(line)
					line=string.split(line)
					
					if(line[0]=="PING"):
						print "Pinged, replying with PONG."
						s.sendall("PONG %s\r\n" % line[1])
					
					if(str(" ".join(line)).find('#thebot') != -1):
						MINION_START = 1
					
					if(line[0] == ':'+HOST and str(" ".join(line)).find(MINION_TEST_NICK) != -1 and str(" ".join(line)).find(MINION_WATCH_CHAN) != -1 and str(" ".join(line)).find(':End of /NAMES list.') == -1 and MINION_CALLED_COMMAND == 1 and str(" ".join(line)).find(MINION_TEST_NICK+' = '+MINION_WATCH_CHAN) != -1):
						# Parse username list!
						print_i("\033[1mExamining username list!\033[0m")
						MINION_CURRENT_USERS = line[5:]
						MINION_MISSING = 0
						MINION_MATCH = 0
						for user in MINION_CURRENT_USERS:
							print_i("Room has: "+user)
							if user[:1] == ':' or user[:1] == '@':
								theuser = user[1:]
								if theuser[:1] == ':' or theuser[:1] == '@':
									tmpuser = theuser[1:]
									theuser = tmpuser
							else:
								theuser = user
							
							if(findelement(theuser, MINION_NICK_SEARCH)):
								MINION_MATCH = MINION_MATCH + 1
								print_i("Found a watched user: "+theuser)
							
						MINION_MISSING = len(MINION_NICK_SEARCH) - MINION_MATCH
						
						print "MINION_MISSING is "+str(MINION_MISSING)+", length is "+str(len(MINION_NICK_SEARCH))
						if MINION_MISSING == len(MINION_NICK_SEARCH):
							# Looks like all the other people are gone! Become active now...
							MINION_READY = 1
				if MINION_START == 1:
					time.sleep(5)
			except Exception, err:
				minorCrashFail(err)
				print_i("MinionBot: Connection failed, exiting.")
				exit(1)
		print_i("Becoming an active bot now!")
		s.sendall("NICK %s\r\n" % MINION_TARGET_NICK)
		IRC_CONNECTED=1
		ForumXMLParseHandler = ForumXMLParse(None, "")
		ForumXMLParseHandler.start()
	else:
		for chan in CHANNELINIT:
			print_r("[IRC] [Autojoin] Joining IRC channel: "+chan)
			joinChannel(chan)
			if (findelement(chan, ANNOUNCECHANS)):
				if (not(findelement(chan, SILENTCHANS))):
					s.sendall("PRIVMSG "+chan+" :I'm BAAAAAAACCCCCKKKKK!!!!!\r\n")
		IRC_CONNECTED=1
		ForumXMLParseHandler = ForumXMLParse(None, "")
		ForumXMLParseHandler.start()

print_d("BOT: Entering main loop")
while 1:
	try:
		readbuffer=readbuffer+s.recv(1024)
	except:
		print_i("Connection closed, exiting.")
		ForumXMLParseHandler.stopThread()
		exit(1)
		break
	temp=string.split(readbuffer, "\n")
	readbuffer=temp.pop()
	
	for line in temp:
		print_r("[IRC] "+line)
		line=string.rstrip(line)
		line=string.split(line)
		
		print_d("[DEBUG] line is "+str(line))
		print_d("[DEBUG] Elements in line:"+str(len(line)))
		print_d("[DEBUG] line[1] is "+line[1])
		print_d("[DEBUG] line[0].split('!')[0][1:] is "+line[0].split('!')[0][1:])
	
		try:
			print_d("[DEBUG] Checking for PING...")
			if(line[0]=="PING"):
				s.sendall("PONG %s\r\n" % line[1])
			
			if NEW_NOTIFICATION_MODE == 1:
				# :irc.mzima.net 433 * New :Nickname is already in use.
				try:
					if (line[1] == "433"):
						NICK = "Omnom"
						s.sendall("NICK %s\r\n" % NICK)
				except:
					# Do nothing :P
					NICK = "New"

			#print_d("[DEBUG] Checking for :hi...")
			#if(len(line)>= 4 and line[3]==":hi"):
			#	s.sendall("JOIN %s \r\n" % CHANNELINIT)
			
			print_d("[DEBUG] Checking for 'End of /MOTD command'...")
			if(str(" ".join(line)).find('End of /MOTD command.') != -1):
				for chan in CHANNELINIT:
					print_r("[IRC] [Autojoin] Joining IRC channel: "+chan)
					joinChannel(chan)
					if (findelement(chan, ANNOUNCECHANS)):
						if (not(findelement(chan, SILENTCHANS))):
							s.sendall("PRIVMSG "+chan+" :I'm BAAAAAAACCCCCKKKKK!!!!!\r\n")
				IRC_CONNECTED=1
				ForumXMLParseHandler = ForumXMLParse(None, "")
				ForumXMLParseHandler.start()
			
			print_d("[DEBUG] Checking for PRIVMSG...")
			if(CleanString(str(" ".join(line))).find('PRIVMSG') != -1): #Call a parsing function 
				print_r("[IRC] [PRIVMSG] Recieved private message, looking at it.")
				parsemsg(str(" ".join(line)))
#				[IRC] :AaronBot!arthur@pool-71-248-45-89.bltmmd.east.verizon.net JOIN :#thebot
			
#			print_d("[DEBUG] Checking for user joining...")
#			if(len(line)>=2 and line[1] == 'JOIN' and findelement(line[0].split('!')[0][1:], OPS)):
#				print_r("[IRC] [AUTO OP] User "+line[0].split('!')[0][1:]+" has logged in and is in the op database,")
#				print_r("[IRC] [AUTO OP] so automatically oping the user.")
#				s.sendall('MODE '+line[2][1:]+' +o '+line[0].split('!')[0][1:]+'\n') 
			
			print_d("[DEBUG] Checking for KICK...")
			if(len(line)>=4 and line[1] == 'KICK' and findelement(line[2], IN_CHANS) and line[3] == NICK and line[4] == ':'+NICK):
				print_r("[IRC] [Autorejoin] Checking if channel is in autoconnect list...")
				if findelement(line[2], AUTOREJOIN_CHANS):
					print_r("[IRC] [Autorejoin] Rejoining "+NICK+"...")
					s.sendall("JOIN %s \r\n" % chan)
#				[IRC] :alberthro!arthur@pool-108-12-167-63.bltmmd.east.verizon.net KICK #thebot Omnom :Omnom
		except Exception, err:
			minorCrashFail(err)
